import { Meta, Canvas } from "@storybook/addon-docs/blocks";
import { Button } from "../../components/Button";
import { ScrollBox } from "../../components/ScrollBox";
import { PasswordValidation } from "./example";

<Meta title="Password validation" />

# Password validation

This is another good example of how layers can provide valuable feedback about a user's input. In this case password validation.
The layer will show up when the input is focussed, and will leave when the input blurs. Also the layer will find the best position on the screen automatically.

<ScrollBox>
  <PasswordValidation />
</ScrollBox>

## The code

First, we need a list of password-requirements:

```jsx
// a record with various predicates which we'll use later on
const validationMap = {
  lowercase: value => /[a-z]/.test(value),
  uppercase: value => /[A-Z]/.test(value),
  special: value => /[\!\@\#\$\%\^\&\*\+\_\-\~]/.test(value),
  numeric: value => /[0-9]/.test(value),
  length: value => value.length >= 8
};
```

Next, a `Requirement` component:

```jsx
function Requirement({ children, type, value }) {
  const predicate = validationMap[type];
  const isValid = predicate(value);

  return (
    <li className="requirement">
      <span>{isValid ? "✔︎" : ""}</span>
      {children}
    </li>
  );
}
```

Finally, the component that brings all things together:

```jsx
function PasswordInput() {
  const [value, setValue] = React.useState("");
  const [hasFocus, setFocus] = React.useState(false);

  const {
    renderLayer,
    triggerProps,
    layerProps,
    arrowProps,
    triggerBounds
  } = useLayer({
    isOpen: hasFocus, // only position when the input-element has focus
    overflowContainer: false, // let the layer stay within the container
    auto: true, // automatically find the best placement
    snap: true, // stick to the possible-placements (don't position in between)
    placement: "top-start", // we prefer to place to layer on the top side when possible
    possiblePlacements: ["top-start", "bottom-start", "right-center", "left-center"],
    triggerOffset: 12, // keep some distance to the input
    containerOffset: 16, // keep some distance to the containers edges
    arrowOffset: 8 // give the arrow some room also
  });

  return (
    <>
      <input
        {...triggerProps}
        type="password"
        value={value}
        onChange={evt => setValue(evt.target.value)}
        onFocus={() => setFocus(true)}
        onBlur={() => setFocus(false)}
        placeholder="Choose a password..."
      />
      {hasFocus && renderLayer(
        <ul
          {...layerProps}
          style={{
            ...layerProps.style,
            width: triggerBounds!.width // keep same with as the input-element
          }}
          className="requirements"
        >
          <div>Choose a secure password</div>
          <Requirement value={value} type="length">
            8 characters
          </Requirement>
          <Requirement value={value} type="uppercase">
            1 uppercase letter
          </Requirement>
          <Requirement value={value} type="lowercase">
            1 lowercase letter
          </Requirement>
          <Requirement value={value} type="special">
            1 special character
          </Requirement>
          <Requirement value={value} type="numeric">
            1 number
          </Requirement>
          <Arrow {...arrowProps} />
        </ul>
      )}
    </>
  );
}
```
